#include "iot_debug.h"
#include "sys_inc.h"
#include "tools/m_sleep.h"
#include "util_tools.h"
#include "config.h"
#include "physicallinkmanager.h"
#include "devicemanager.h"
#include "sensormanager.h"
#include "modulemanager.h"
#include "string_match.h"
#include "version.h"

#include <fstream>
#include <sstream>
#include <signal.h>
#include "logger.h"

int com_index = -1;
int realcom_index = -1;
int dev_index = -1;
int ErrCode = 0;
char ErrMsg[1024] = {0};
std::string StartTime;

#if PLATFORM_NUM < 3
const char Const_Command[] = "ps | grep \"SyyGather\" | grep -v \"SyyGather.log\" | grep -v \"SyyGather.sh\" | grep -v \"gdb\" | grep -v \"grep\" | grep -v \"install.sh\" | grep -v \"appm\" | wc -l";
#else
const char Const_Command[] = "ps aux | grep \"SyyGather\" | grep -v \"SyyGather.log\" | grep -v \"SyyGather.sh\" | grep -v \"gdb\" | grep -v \"grep\" | grep -v \"install.sh\" | grep -v \"appm\" | wc -l";
#endif
extern void downLinkTest(void);

std::map<uint8_t, std::string> RealUartlist_;

static const char* Check_Process(const char* Cmd)
{
    static std::string str;
    FILE    *fp;
    char    buf[1024] = {0};
    str = std::string("");
    fp = popen((const char *)Cmd, "r");

    while(fgets((char *)buf, sizeof(buf), fp) != NULL)
    {
        str.append(buf);
    }

    if(fp != NULL)
    {
        pclose(fp);
    }

    return str.c_str();
}

static bool Parse_Cmd(int argc, char **argv)
{
    {
        //固化端口参数
        RealUartlist_[-1] = "Unknown";
        RealUartlist_[0]  = "SLOT0_RS485-1";
        RealUartlist_[1]  = "SLOT0_RS485-2";
        RealUartlist_[2]  = "SLOT0_RS485-3";
        RealUartlist_[3]  = "SLOT0_RS485-4";
        RealUartlist_[4]  = "SLOT1_RS485-1";
        RealUartlist_[5]  = "SLOT1_RS485-2";
        RealUartlist_[6]  = "SLOT1_RS485-3";
        RealUartlist_[7]  = "SLOT1_RS485-4";
        RealUartlist_[8]  = "SLOT2_RS485-1";
        RealUartlist_[9]  = "SLOT2_RS485-2";
        RealUartlist_[10] = "SLOT2_RS485-3";
        RealUartlist_[11] = "SLOT2_RS485-4";
        RealUartlist_[12] = "SLOT3_RS485-1";
        RealUartlist_[13] = "SLOT3_RS485-2";
        RealUartlist_[14] = "SLOT3_RS485-3";
        RealUartlist_[15] = "SLOT3_RS485-4";
        RealUartlist_[16] = "SLOT4_RS485-1";
        RealUartlist_[17] = "SLOT4_RS485-2";
        RealUartlist_[18] = "SLOT4_RS485-3";
        RealUartlist_[19] = "SLOT4_RS485-4";
        RealUartlist_[20] = "SLOT5_RS485-1";
        RealUartlist_[21] = "SLOT5_RS485-2";
        RealUartlist_[22] = "SLOT5_RS485-3";
        RealUartlist_[23] = "SLOT5_RS485-4";
        RealUartlist_[24] = "SLOT1_LCC";
        RealUartlist_[25] = "SLOT2_LCC";
    }

    int i;
    std::string tmp;

    if(argc > 1)
    {
        if(argc == 2)
        {
            if((strstr(argv[1], "help") != 0) || (strstr(argv[1], "-h") != 0) || (strstr(argv[1], "-?") != 0))
            {
                //-h help 显示命令列表
                //-d 显示串口设备通讯，后面跟参数具体代表哪一路串口
                //-v 显示app版本号
                //其它参数无效
                printf("**************Para List**************\n");
                printf("-d p.n communicate uart p device n, -d p communicate uart m all device\n");
                printf("-v show app version\n");
                printf("-p show uart List\n");
                printf("-l x show uart x device list. -l show all device list\n");
                exit(0);
            }
            else if(strstr(argv[1], "-l") != 0)
            {
                DeviceManager::mgr()->ShowDeviceList(-1);
                exit(0);
            }
            else if(strstr(argv[1], "-p") != 0)
            {
                printf(" port            index\n");
                printf("SLOTn_RS485-m     n-m\n");
                printf("SLOTn_LCC         n-LCC\n");
                printf("\nExample\n");
                printf("./SyyGather -d 4-1\n");
                printf("./SyyGather -d 1-LCC\n");
                exit(0);
            }
            else
            {
                printf("para error\n");
                exit(0);
            }
        }
        else if(argc == 3)
        {
            if (strstr(argv[1], "-d") != 0)
            {
                tmp = argv[2];
                std::string::size_type pos = tmp.find('-');
                if (tmp.find('-') != std::string::npos)
                {
                    if (tmp.find('L') != std::string::npos)
                    {
                        com_index = atoi(tmp.c_str());
                        if (com_index >= MIN_OF_SLOT_ID && com_index < 2)
                        {
                            tmp.erase(0, pos + 1);
                            com_index += 24 - 1;
                        }
                        else
                        {
                            com_index = -1;
                        }
                    }
                    else
                    {
                        com_index = atoi(tmp.c_str());
                        if (com_index >= MIN_OF_SLOT_ID && com_index <= MAX_OF_SLOT_ID)
                        {
                            com_index = (com_index) * 4;
                            tmp.erase(0, pos + 1);
                            int id = atoi(tmp.c_str());
                            if (id >= MIN_OF_UART_ID && id <= MAX_OF_UART_ID)
                            {
                                com_index += id - 1;
                            }
                            else
                            {
                                com_index = -1;
                            }
                        }
                        else
                        {
                            com_index = -1;
                        }
                    }
                }
                else
                {
                    com_index = atoi(tmp.c_str());
                }

                pos = tmp.find('.');
                if (pos != std::string::npos)
                {
                    tmp.erase(0, pos + 1);
                    dev_index = atoi(tmp.c_str());
                }

                return true;
            }
            else if (strstr(argv[1], "-l") != 0)
            {
                tmp = argv[2];
                std::string::size_type pos = tmp.find('-');
                if (tmp.find('-') != std::string::npos)
                {
                    if (tmp.find('L') != std::string::npos)
                    {
                        com_index = atoi(tmp.c_str());
                        tmp.erase(0, pos + 1);
                        com_index += 24 - 1;
                    }
                    else
                    {
                        com_index = atoi(tmp.c_str());
                        com_index = (com_index) * 4;
                        tmp.erase(0, pos + 1);
                        com_index += atoi(tmp.c_str()) - 1;
                    }
                }
                else
                {
                    com_index = atoi(tmp.c_str());
                }

                realcom_index = PhysicalLinkManager::mgr()->devIndex(RealUartlist_[com_index].c_str());

                if (realcom_index < 0)
                {
                    printf("not found the %s's devices\n", argv[2]);
                    exit(0);
                }

                DeviceManager::mgr()->ShowDeviceList(realcom_index);
                exit(0);
            }
        }
    }

    return false;
}

static void Get_Compile_Date_Base(int *Year, int *Month, int *Day)
{
    int i;
    const char *pMonth[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    const char Date[12] = __DATE__;//取编译时间

    for(i = 0; i < 12; i++)
    {
        if(memcmp(Date, pMonth[i], 3) == 0)
        {
            *Month = i + 1;
            i = 12;
        }

        *Year = (int)atoi(Date + 7); //Date[9]为２位年份，Date[7]为完整年份
        *Day = (int)atoi(Date + 4);
    }
}

static void Show_Version_Info(bool isPrt, bool isLog)
{
    int  Year, Month, Day;
    char g_date_buf[32];

    Get_Compile_Date_Base(&Year, &Month, &Day);//取编译时间
    sprintf(g_date_buf, "%d-%02d-%02d", Year, Month, Day);

    if (isPrt)
    {
        printf("%s %s %s\n", VERSION, g_date_buf, __TIME__);
    }

    if (isLog)
    {
        log_info("%s %s %s\n", VERSION, g_date_buf, __TIME__);
    }
}



int check_system_license(void)
{
    const char* cmd = "/rom/usr/sbin/license_tool check /tmp/sysinfo/system.license";
    char  data[512] = {0};
    int OK = -1;

    FILE *fp = popen(cmd, "r");
    if (fp)
    {
        int nread = fread(data, 1, sizeof(data), fp);
        if (strstr(data, "success"))
        {
            OK = 0;
        }
        pclose(fp);
    }
    return OK;
}

int main(int argc, char *argv[])
{
    int i, Ret;
    bool DebugFlag = false;
    bool dump_dev_data = true;
    std::string name(APP_NAME);
    std::string debug("");

    Show_Version_Info(true, false);

    if(argc == 2)
    {
        if(strstr(argv[1], "-v") != 0)
        {
            //显示版本信息
            exit(0);
        }
    }

    Logger::getInstance();

    Show_Version_Info(false, true);
    StartTime = GetTime();

    for(i = 0; i < argc; i++)
    {
        if(strstr(argv[i], "-D") != 0)
        {
            argc = 3;
            dump_dev_data = false;
        }
    }

    if (check_system_license() != 0)
    {
        log_error("License unavailable!\n");
        exit(-1);
    }

    //检查看是否运行多个SyyGather进程
    const char *Str =  Check_Process(Const_Command);

    Ret = atoi((const char *)Str);
    if(Ret > 1)
    {
        //保证整个系统只运行1个SyyGather进程
        ErrCode = APP_IS_RUN;
        Print_err_log(ErrCode);
        printf("SyyGather already run, ErrCode :%d\n", ErrCode);
        exit(0);
    }

    //必须初始链接MQTT成功
    while (0 != sensormanager::getInstance()->init(name.c_str()))
    {
        log_info("Will try connecting to the MQTT again in 5 seconds\n");
        sleep(2);
        sensormanager::getInstance()->deinit();
        sleep(3);
    }

    if (!sensormanager::getInstance()->logined())
    {
        log_info("Failed to connect to MQTT\n");
        goto exitCode;
    }

    DeviceManager::mgr();

    log_info("starting DataCenter servring\n");
    //开始处理，仅Broker重链和扫码易联内容
    sensormanager::getInstance()->startServer();

    log_info("load gather_config.json\n");
    PhysicalLinkManager::mgr()->loadConfig();

    log_info("create com map\n");
    PhysicalLinkManager::mgr()->createCom();

    //程序启动首先检查一次模组信息文件.更新串口映射文件comRemap
    log_info("check module status\n");
    ModuleManager::getInstance()->loop();

    log_info("load comSettings\n");
    if (!PhysicalLinkManager::mgr()->loadCom())
    {
        log_info("comSettings.json load failed,err code :%d\n", ErrCode);
        goto PROJ_ERR;
    }

    {
        log_info("load DeviceList\n");
        int devNum = DeviceManager::mgr()->loadDevice();
        if (devNum == -1 || devNum == -2)
        {
            log_info("DeviceList.json is empty,please config first\n");
            goto PROJ_ERR;
        }
        else{}
    }

    DebugFlag = Parse_Cmd(argc, argv);
    if(DebugFlag)
    {
        realcom_index = PhysicalLinkManager::mgr()->portIndex(RealUartlist_[com_index].c_str());

        if(com_index == 10)
        {
            //modbus-tcp协议
            for(i = 0; i < PhysicalLinkManager::mgr()->devNum(); i++)
            {
                if(!PhysicalLinkManager::mgr()->getDevice(i)->comSettings()->is_uart)
                {
                    realcom_index = i;
                    break;
                }
            }
        }

        if(realcom_index < 0)
        {
            if (com_index == 9)
            {
                printf("comSettings.json not config DI:127.0.0.1:36072!\n");
            }
            else
            {
                printf("comSettings.json not config %s!\n", RealUartlist_[com_index].c_str());
            }
            return 0;

        }
        DeviceManager::mgr()->setDebugDevice(realcom_index, dev_index);
        PhysicalLinkManager::mgr()->setDumpFlag(realcom_index, true);
    }

    if(DebugFlag)
    {
        //进入调试模式
        DeviceManager::mgr()->startGather();
        while (1)
        {
            if(dump_dev_data)
                downLinkTest();

            sleep(2);
        }
    }
    else
    {
        log_info("load SouthDeviceList\n");
        if (!sensormanager::getInstance()->loadSensors())
        {
            log_info("SouthDeviceList.json load failed,err code :%d\n", ErrCode);
            goto PROJ_ERR;
        }

        log_info("check models\n");
        while (!sensormanager::getInstance()->checkModels())
        {
            log_info("check models failed,err code :%d\n", ErrCode);
            mSleep(5000);
        }

        log_info("check devs\n");
        while (!sensormanager::getInstance()->checkDevs())
        {
            log_info("check devs failed,err code :%d\n", ErrCode);
            mSleep(5000);
        }

        //注册完模型及设备后启动采集线程
        log_info("starting gather\n");
        DeviceManager::mgr()->startGather();

        //启动数据中心处理线程
        log_info("starting DataCenter start reporting\n");
        sensormanager::getInstance()->startReport();
    }
PROJ_ERR:
    sensormanager::getInstance()->startSMYL();
    while (true)
    {
        sleep(1);
    }

exitCode:
    log_warn("SyyGather exit\n");
    return 0;
}
